package com.service.healthycode.service.impl;

import com.alibaba.excel.EasyExcelFactory;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.service.config.utils.ModelMapperUtil;
import com.service.config.utils.Result;
import com.service.healthycode.dao.AdminDao;
import com.service.healthycode.dao.DangerUserDao;
import com.service.healthycode.dao.TerminalListDao;
import com.service.healthycode.dao.TouchUserDao;
import com.service.healthycode.dto.*;
import com.service.healthycode.entity.AdminInfo;
import com.service.healthycode.entity.DangerUser;
import com.service.healthycode.entity.TerminalList;
import com.service.healthycode.entity.TouchInfo;
import com.service.healthycode.service.DangerUserService;
import com.service.healthycode.vo.QueryByMacVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: hjl
 * @date: 2022/04/14 10:59
 * @description
 */
@Service
@Slf4j
public class DangerUserServiceImpl implements DangerUserService {
    @Resource
    private DangerUserDao dangerUserDao;
    @Resource
    private TouchUserDao touchUserDao;
    @Resource
    private TerminalListDao terminalListDao;
    @Resource
    private AdminDao adminDao;
    @Value("${spring.fileUrl}")
    String fileUrl;
    @Value("${spring.filePath}")
    String filePath;

    private final Integer PAGE_SIZE = 10;

    /**
     * 查询终端在一段时间内的行程轨迹
     * @param mac 终端mac
     * @param start 开始时间
     * @param end 结束时间
     * @return 结果集
     * @throws ParseException
     */
    @Override
    public Result queryDangerUserByMac(String mac,String start,String end) throws ParseException {
        SimpleDateFormat sf= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date startTime = sf.parse(start);
        Date endTime = sf.parse(end);

        DangerUser dangerUser = new DangerUser();
        dangerUser.setTerminalMac(mac);
        dangerUser.setStartDate(startTime);
        dangerUser.setEndDate(endTime);
        List<TerminalList> terminalLists = terminalListDao.queryTerminalByTime(dangerUser);
        List<TerminalListDto> terminalListDtos = ModelMapperUtil.strictMapList(terminalLists, TerminalListDto.class);

        terminalListDtos.forEach(t->{
            if (t.getOffLineTime()==null){
                long min = getDatePoor(t.getOnLineTime(), new Date());
                t.setStayTime(min);
            }else {
                long min = getDatePoor(t.getOnLineTime(), t.getOffLineTime());
                t.setStayTime(min);
            }
        });
        return Result.ok().setData(terminalListDtos);
    }

    @Override
    public Result exportDangerListByCondition(String mac, String startTime, String endTime) throws ParseException {
        Object data = this.queryDangerUserByMac(mac, startTime, endTime).getData();
        if (!ObjectUtils.isEmpty(data)){
            List<TerminalListDto> terminalListDtos = ModelMapperUtil.strictMapList(data, TerminalListDto.class);
            List<ExportTerminalDto> exportTerminalDtos = ModelMapperUtil.strictMapList(terminalListDtos, ExportTerminalDto.class);

            String currentTime = Long.toString(System.currentTimeMillis());
            EasyExcelFactory.write(filePath+"终端轨迹"+currentTime+".xlsx", ExportTerminalDto.class).sheet().doWrite(exportTerminalDtos);
            return Result.ok().setData(fileUrl+"终端轨迹"+currentTime+".xlsx");
        }
        return Result.failure("无数据");
    }

    /**
     * 查看管理员录入的风险终端
     * @return
     */
    @Override
    public Result queryDangerByAdmin(Integer page) {
        Map<String,Object> map = new HashMap<>(16);
        PageHelper.startPage(page,PAGE_SIZE);
        List<DangerUser> dangerUsers = dangerUserDao.queryAllDangerUser();
        PageInfo<DangerUser> pageInfo = new PageInfo<DangerUser>(dangerUsers);
        List<DangerDto> dangerDtos = new ArrayList<>();
        if (!dangerUsers.isEmpty()){
            dangerDtos = ModelMapperUtil.strictMapList(dangerUsers, DangerDto.class);
            dangerDtos.forEach(d->d.setOrigin(0));
        }

        map.put("dangers",dangerDtos);
        map.put("pageSize",PAGE_SIZE);
        map.put("pageIndex",page);
        map.put("totalRecords",pageInfo.getTotal());
        map.put("totalPages",pageInfo.getPages());
        return Result.ok().setData(map);
    }

    /**
     * 查看下一级感染终端
     * @param ids 该终端的id
     * @param origin 判断是管理员录入的还是被感染的
     * @return 结果集
     */
    @Override
    public Result queryNextLevel(List<String> ids, Integer origin,Integer page) {
        if (!origin.equals(0) &&!origin.equals(1) &&!origin.equals(2) ){
            return Result.failure("数据来源有误!");
        }
        Map<String,Object> map = new HashMap<>(16);
        List<QueryByMacVo> voList = new ArrayList<>();
        PageInfo<TouchInfo> pageInfo = null;
        if (origin.equals(0) || origin.equals(2)){
            //查询这些id的danger信息
            List<DangerUser> dangerUsers = dangerUserDao.queryByIds(ids);
            if (!dangerUsers.isEmpty()){
                //获取这些danger信息的id，组成集合
                List<String> dangerIds = dangerUsers.stream().map(DangerUser::getId).collect(Collectors.toList());
                //通过id集合查询所有下一层touch信息
                PageHelper.startPage(page,PAGE_SIZE);
                List<TouchInfo> touchs = touchUserDao.queryNextByDangerIds(dangerIds);
                pageInfo = new PageInfo<TouchInfo>(touchs);
                if (!touchs.isEmpty()){
                    for (TouchInfo touch : touchs) {
                        Result result = this.queryByMac(touch.getTerminalMac());
                        if (result != null && result.getData() != null)
                        {
                            List<QueryByMacVo> vos = ModelMapperUtil.strictMapList(result.getData(), QueryByMacVo.class);
                            if (vos != null && vos.size()>0){
                                voList.add(vos.get(0));
                            }
                        }
                    }
                }
            }
        }
        if (origin.equals(1) || origin.equals(2)){
            //查询这些id的touch信息
            List<TouchInfo> touchInfos = touchUserDao.queryTouchByIds(ids);
            if (!touchInfos.isEmpty()){
                //将这些touch信息的id组成集合
                List<String> touchIds = touchInfos.stream().map(TouchInfo::getId).collect(Collectors.toList());
                //通过id集合查询所有下一层touch信息
                PageHelper.startPage(page,PAGE_SIZE);
                List<TouchInfo> touchs = touchUserDao.queryNextByTouchIds(touchIds);
                pageInfo = new PageInfo<TouchInfo>(touchs);
                if (!touchs.isEmpty()){
                    for (TouchInfo touch : touchs) {
                        Result result = this.queryByMac(touch.getTerminalMac());
                        if (result != null && result.getData() != null)
                        {
                            List<QueryByMacVo> vos = ModelMapperUtil.strictMapList(result.getData(), QueryByMacVo.class);
                            if (vos != null && vos.size()>0){
                                voList.add(vos.get(0));
                            }
                        }
                    }
                }
            }
        }
        map.put("vo",voList);
        map.put("pageSize",PAGE_SIZE);
        map.put("pageIndex",page);
        map.put("totalRecords",pageInfo.getTotal());
        map.put("totalPages",pageInfo.getPages());
        return Result.ok().setData(voList);
    }

    /**
     * 查看上一级感染终端
     * @param ids 终端id
     * @param origin 判断是管理员录入的还是被感染的
     * @return 结果集
     */
    @Override
    public Result queryAboveLevel(List<String> ids, Integer origin) {
        List<QueryByMacVo> voList = new ArrayList<>();
        List<TouchInfo> touchInfos;
        if (origin.equals(0)){
            return Result.failure("当前终端是感染源终端，无上级感染源");
        }else if (origin.equals(1) || origin.equals(2)){
            //被感染，从touch_info表查询
            //通过id集合查询touch_info中的终端
            touchInfos = touchUserDao.queryTouchByIds(ids);
            if (!touchInfos.isEmpty()){
                //上级还是touch表中的数据
                List<TouchInfo> touchs = touchInfos.stream().filter(t -> t.getParentId() != null && !t.getParentId().equals("")).collect(Collectors.toList());
                //上级还是danger中的数据
                List<TouchInfo> dangers = touchInfos.stream().filter(t -> t.getDangerId() != null && !t.getDangerId().equals("")).collect(Collectors.toList());

                if (!touchs.isEmpty()){
                    List<String> parentIds = touchs.stream().map(TouchInfo::getParentId).collect(Collectors.toList());
                    List<TouchInfo> touchParents = touchUserDao.queryTouchByIds(parentIds);
                    if (!touchParents.isEmpty()){
                        for (TouchInfo touchParent : touchParents) {
                            Result result = this.queryByMac(touchParent.getTerminalMac());
                            if (result != null && result.getData() != null)
                            {
                                List<QueryByMacVo> vos = ModelMapperUtil.strictMapList(result.getData(), QueryByMacVo.class);
                                if (vos != null && vos.size()>0){
                                    voList.add(vos.get(0));
                                }
                            }
                        }
                    }
                }
                if (!dangers.isEmpty()){
                    List<String> dangerIds = dangers.stream().map(TouchInfo::getDangerId).collect(Collectors.toList());
                    List<DangerUser> dangerParents = dangerUserDao.queryByIds(dangerIds);
                    if (!dangerParents.isEmpty()){
                        for (DangerUser dangerParent : dangerParents) {
                            Result result = this.queryByMac(dangerParent.getTerminalMac());
                            if (result != null && result.getData() != null)
                            {
                                List<QueryByMacVo> vos = ModelMapperUtil.strictMapList(result.getData(), QueryByMacVo.class);
                                if (vos != null && vos.size()>0){
                                    voList.add(vos.get(0));
                                }
                            }
                        }
                    }
                }
            }
        }else {
            return Result.failure("数据来源有误");
        }

        Map<Integer, List<QueryByMacVo>> collect = voList.stream().filter(v1 -> voList.stream().filter(v2 -> v2.getTerminalMac().equals(v1.getTerminalMac())).count() > 1).collect(Collectors.groupingBy(QueryByMacVo::getStatus));
        List<QueryByMacVo> queryByMacVos = new ArrayList<>();
        collect.entrySet().forEach(e->queryByMacVos.add(e.getValue().stream().max(Comparator.comparing(QueryByMacVo::getStatus)).get()));
        collect.entrySet().forEach(e->voList.removeAll(e.getValue()));
        voList.addAll(queryByMacVos);
        return Result.ok().setData(voList);
    }

    /**
     * 抽取公共代码
     * @param touchInfos
     * @return
     */
    private void getTouchInfos(List<TouchInfo> touchInfos) {
        Map<String, List<TouchInfo>> collect2 = touchInfos.stream().filter(d -> touchInfos.stream().filter(d2 -> d2.getTerminalMac().equals(d.getTerminalMac())).count() > 1)
                .collect(Collectors.groupingBy(TouchInfo::getTerminalMac));
        List<TouchInfo> touchInfos1 = new ArrayList<>();
        collect2.entrySet().forEach(e -> touchInfos1.add(e.getValue().stream().max(Comparator.comparing(TouchInfo::getStatus)).get()));
        collect2.entrySet().forEach(e -> touchInfos.removeAll(e.getValue()));
        touchInfos.addAll(touchInfos1);
    }


    /**
     * 通过mac地址查询终端状态(状态优先级优先，查询录入表danger_user,查询接触表touch_user,同时有多个终端的情况要全部列出来)
     * @param mac mac地址
     * @return 结果集
     */
    @Override
    public Result queryByMac(String mac) {
        QueryByMacVo vo=null;
        Map<String, List<String>> map = new HashMap<>();
        //1、查询录入表
        List<DangerUser> dangerUsers = dangerUserDao.queryByMac(mac);
        DangerTerminalDto terminalDto = null;
        if (!dangerUsers.isEmpty()){
            //状态等级最高的
            Optional<DangerUser> op = dangerUsers.stream().max(Comparator.comparing(DangerUser::getStatus));
            if (op.isPresent()){
                terminalDto = new DangerTerminalDto();
                Integer status = op.get().getStatus();
                List<DangerUser> dangerList = dangerUsers.stream().filter(d -> d.getStatus().equals(status)).collect(Collectors.toList());
                terminalDto.setTerminalMac(dangerList.get(0).getTerminalMac());
                terminalDto.setStatus(dangerList.get(0).getStatus());
                terminalDto.setOrigin(0);
                List<String> ids = new ArrayList<>();
                dangerList.forEach(d->ids.add(d.getId()));
                terminalDto.setIds(ids);
            }
        }
        //2、查询接触表
        List<TouchInfo> touchInfos = touchUserDao.queryByMac(mac);
        TouchDto touchDto = null;
        if (!touchInfos.isEmpty()){
            Optional<TouchInfo> op = touchInfos.stream().max(Comparator.comparing(TouchInfo::getStatus));
            if (op.isPresent()){
                touchDto = new TouchDto();
                Integer status = op.get().getStatus();
                List<TouchInfo> touchs = touchInfos.stream().filter(s -> s.getStatus().equals(status)).collect(Collectors.toList());
                touchDto.setTerminalMac(touchs.get(0).getTerminalMac());
                touchDto.setStatus(touchs.get(0).getStatus());
                touchDto.setOrigin(1);
                List<String> ids = new ArrayList<>();
                touchs.forEach(t->ids.add(t.getId()));
                touchDto.setIds(ids);
            }
        }

        if (terminalDto!=null && touchDto != null){
            if (terminalDto.getStatus().equals(touchDto.getStatus()) ){
                vo = ModelMapperUtil.strictMap(terminalDto, QueryByMacVo.class);
                //2的意思就是既来源于danger，也来源于touch
                vo.setOrigin(2);
                map.put("danger",terminalDto.getIds());
                map.put("touch",touchDto.getIds());
                vo.setIdMap(map);
            }else if (touchDto.getStatus()>terminalDto.getStatus()){
                vo = ModelMapperUtil.strictMap(touchDto, QueryByMacVo.class);
                map.put("danger",new ArrayList<>());
                map.put("touch",touchDto.getIds());
                vo.setIdMap(map);
            }else if (touchDto.getStatus()<terminalDto.getStatus()){
                vo = ModelMapperUtil.strictMap(terminalDto, QueryByMacVo.class);
                map.put("danger",terminalDto.getIds());
                map.put("touch",new ArrayList<>());
                vo.setIdMap(map);
            }
        }else if (terminalDto==null && touchDto != null){
            vo = ModelMapperUtil.strictMap(touchDto, QueryByMacVo.class);
            map.put("danger",new ArrayList<>());
            map.put("touch",touchDto.getIds());
            vo.setIdMap(map);
        }else if (terminalDto!=null && touchDto == null){
            vo = ModelMapperUtil.strictMap(terminalDto, QueryByMacVo.class);
            map.put("danger",terminalDto.getIds());
            map.put("touch",new ArrayList<>());
            vo.setIdMap(map);
        }else if (terminalDto==null && touchDto == null){
            //danger表和touch表中都没有查到该终端的数据，这就需要从terminal表中查询该mac
            List<TerminalList> terminalLists = terminalListDao.queryByTerminalMac(mac);
            if (!terminalLists.isEmpty()){
                vo = ModelMapperUtil.strictMap(terminalLists.get(0), QueryByMacVo.class);
                vo.setStatus(0);
            }else {
                return Result.failure("未查询到该终端信息");
            }

        }

        //应前端要求，返回数组
        List<QueryByMacVo> vos=new ArrayList<>();
        vos.add(vo);
        return Result.ok().setData(vos);
    }

    /**
     * 查询各类风险终端
     * @return
     */
    @Override
    public Result queryDangerUserOfKind(Integer status,String mac) {
        List<DangerDto> dangerDtos = new ArrayList<>();
        //查询所有风险用户
        List<DangerUser> dangerUserList = dangerUserDao.queryAllDangerUser();
        //查询接触表
        List<TouchInfo> touchInfos = touchUserDao.queryAllDangerUser();

        if (dangerUserList != null){
            List<DangerDto> dangerDtos1 = new ArrayList<>();

            dangerUserList.forEach(d->{
                DangerDto dangerDto = new DangerDto();
                dangerDto.setStatus(d.getStatus());
                dangerDto.setTerminalMac(d.getTerminalMac());
                dangerDto.setOrigin(0);
                dangerDto.setId(d.getId());
                dangerDto.setStartDate(d.getStartDate());
                dangerDto.setEndDate(d.getEndDate());
                dangerDto.setStayTime(getDatePoor(d.getStartDate(),d.getEndDate()));
                dangerDto.setTouchStartTime(d.getStartDate());
                dangerDto.setTouchEndTime(d.getEndDate());
                dangerDtos1.add(dangerDto);
            });
            dangerDtos.addAll(dangerDtos1);
        }
        if (touchInfos != null){
            List<DangerDto> dangerDtos1 = ModelMapperUtil.strictMapList(touchInfos, DangerDto.class);
            dangerDtos1.forEach(d->d.setOrigin(1));
            dangerDtos.addAll(dangerDtos1);
        }

        //同一个终端选择级别最高的
        Map<String, List<DangerDto>> collect = dangerDtos.stream().filter(d -> dangerDtos.stream().filter(d2 -> d2.getTerminalMac().equals(d.getTerminalMac())).count() > 1)
                .collect(Collectors.groupingBy(DangerDto::getTerminalMac));
        List<DangerDto> dangerDtos1 = new ArrayList<>();
        collect.entrySet().forEach(e->dangerDtos1.add(e.getValue().stream().max(Comparator.comparing(DangerDto::getStatus)).get()));
        collect.entrySet().forEach(e->dangerDtos.removeAll(e.getValue()));

        dangerDtos.addAll(dangerDtos1);

        if (status != null || (mac != null && !mac.equals(""))){
            List<DangerDto> dangers = new ArrayList<>();
            if (status != null && mac != null && !mac.equals("")){
                dangers = dangerDtos.stream().filter(d -> d.getStatus().equals(status) && d.getTerminalMac().equals(mac)).collect(Collectors.toList());
            }else if (status != null){
                dangers = dangerDtos.stream().filter(d->d.getStatus().equals(status)).collect(Collectors.toList());
            }else if(mac != null && !mac.equals("")){
                dangers = dangerDtos.stream().filter(d->d.getTerminalMac().equals(mac)).collect(Collectors.toList());
            }

            List<DangerDto> collect1 = dangers.stream().sorted(Comparator.comparing(DangerDto::getStatus).reversed()).collect(Collectors.toList());
            return Result.ok().setData(collect1);
        }
        List<DangerDto> collect1 = dangerDtos.stream().sorted(Comparator.comparing(DangerDto::getStatus).reversed()).collect(Collectors.toList());
        return Result.ok().setData(collect1);
    }

    /**
     * 查询昨日各类新增
     * @return 结果集
     */
    @Override
    public Result queryIncrementOfToday() {
        List<DangerDto> dangerDtos = new ArrayList<>();
        //查询所有风险用户
        List<DangerUser> dangerUserList = dangerUserDao.queryIncrementOfToday();
        //查询接触表
        List<TouchInfo> touchInfos = touchUserDao.queryIncrementOfToday();

        if (dangerUserList != null){
            dangerDtos.addAll(ModelMapperUtil.strictMapList(dangerUserList,DangerDto.class));
        }
        if (touchInfos != null){
            dangerDtos.addAll(ModelMapperUtil.strictMapList(touchInfos,DangerDto.class));
        }

        Map<String, List<DangerDto>> collect = dangerDtos.stream().filter(d -> dangerDtos.stream().filter(d2 -> d2.getTerminalMac().equals(d.getTerminalMac())).count() > 1)
                .collect(Collectors.groupingBy(DangerDto::getTerminalMac));
        List<DangerDto> dangerDtos1 = new ArrayList<>();
        collect.entrySet().forEach(e->dangerDtos1.add(e.getValue().stream().max(Comparator.comparing(DangerDto::getStatus)).get()));
        collect.entrySet().forEach(e->dangerDtos.removeAll(e.getValue()));

        dangerDtos.addAll(dangerDtos1);

        int total=0;
        if (null != this.queryDangerUserOfKind(null,"").getData()){
            List<DangerDto> dangerDtos2 = ModelMapperUtil.strictMapList(this.queryDangerUserOfKind(null,"").getData(), DangerDto.class);
            total = dangerDtos2.size();
        }

        Map<String, Integer> map=new HashMap<>();
        map.put("confirm", (int) dangerDtos.stream().filter(d->d.getStatus().equals(4)).count());
        map.put("touch", (int) dangerDtos.stream().filter(d->d.getStatus().equals(3)).count());
        map.put("total", dangerDtos.size());
        return Result.ok().setData(map);
    }

    @Override
    public Result exportDangerList() {
        /**
         * 从danger表查询所有风险终端
         */
        List<DangerUser> dangerUsers = dangerUserDao.queryAllDangerUser();
        if (!dangerUsers.isEmpty()){
            List<ExportDangerDto> exportDangerList = ModelMapperUtil.strictMapList(dangerUsers, ExportDangerDto.class);

            String currentTime = Long.toString(System.currentTimeMillis());
            EasyExcelFactory.write(filePath+"风险清单"+currentTime+".xlsx", ExportDangerDto.class).sheet().doWrite(exportDangerList);
            return Result.ok().setData(fileUrl+"风险清单"+currentTime+".xlsx");
        }
        return Result.failure("无数据");
    }

    /**
     * 通过id查询指定终端信息
     */
    @Override
    public Result queryDangerUserById(String id,Integer origin) {
        if (origin.equals(1)){
            TouchInfo touchInfo = touchUserDao.queryTouchUserById(id);
            DangerUser dangerUser = dangerUserDao.queryById(touchInfo.getDangerId());
            dangerUser.setTerminalMac(touchInfo.getTerminalMac());
            List<TerminalList> terminalLists = terminalListDao.queryByTimeAndMac(dangerUser);
            List<TerminalListDto> terminalListDtos = ModelMapperUtil.strictMapList(terminalLists, TerminalListDto.class);
            terminalListDtos.stream().filter(t->t.getId().equals(touchInfo.getTerminalId())).forEach(t2->{
                t2.setTouchTime(touchInfo.getTouchTime());
                t2.setTouchStartTime(touchInfo.getTouchStartTime());
                t2.setTouchEndTime(touchInfo.getTouchEndTime());
            });
            terminalListDtos.forEach(t->t.setTerminalMac(t.getTerminalMac()));
            return Result.ok().setData(terminalListDtos);
        }else if (origin.equals(0)){
            DangerUser dangerUser = dangerUserDao.queryDangerUserById(id);
            List<TerminalList> terminalLists = terminalListDao.queryByTimeAndMac(dangerUser);
            List<TerminalListDto> terminalListDtos = ModelMapperUtil.strictMapList(terminalLists, TerminalListDto.class);
            terminalListDtos.forEach(t->t.setTerminalMac(t.getTerminalMac()));
            return Result.ok().setData(terminalListDtos);
        }
        return Result.failure("参数有误");
    }

    /**
     * 计算时间差。返回分钟数
     * @param startDate 开始时间
     * @param endDate 结束时间
     * @return 时间差(分钟)
     */
    public long getDatePoor(Date startDate,Date endDate){
        return (endDate.getTime() - startDate.getTime()) / (1000 * 60);
    }
}
